package com.cqjybigscreen.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqjybigscreen.mapper.AdsCqwlChannelMapper;
import com.cqjybigscreen.pojo.dto.*;
import com.cqjybigscreen.pojo.entity.AdsCqwlChannel;
import com.cqjybigscreen.pojo.vo.BoxTrendVO;
import com.cqjybigscreen.pojo.vo.BoxVolumeVO;
import com.cqjybigscreen.pojo.vo.LineNameSumMarVO;
import com.cqjybigscreen.pojo.vo.YearStatisticsVO;
import com.cqjybigscreen.service.AdsCqwlChannelService;
import com.cqjybigscreen.utils.TimesUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 四向通道汇总 服务实现类
 * </p>
 *
 * @author RaoChang
 */
@Service
@AllArgsConstructor
public class AdsCqwlChannelServiceImpl extends ServiceImpl<AdsCqwlChannelMapper, AdsCqwlChannel> implements AdsCqwlChannelService {

    private final AdsCqwlChannelMapper adsCqwlChannelMapper;

    /**
     * 获取箱量走势图
     *
     * @return List<BoxVolumeVO>
     */
    @Override
    public List<BoxVolumeVO> getBoxVolume(BoxVolumeDTO dto) {
        String lastMonthStartTime;
        List<LocalDate> lastMonthDays;
        //标记区分sql查询按照天还是月
        boolean b = true;
        Integer type = dto.getType();
        if (type == 1) {
            lastMonthStartTime = TimesUtils.getLastMonthStartTime(LocalDate.now());
            //获取最近一个月每一天的Date类型的日期
            lastMonthDays = TimesUtils.getLastMonthDays(LocalDate.now());
        } else if (type == 2) {
            //90天数据
            lastMonthStartTime = TimesUtils.getLastThreeMonthStartTime(LocalDate.now());
            lastMonthDays = TimesUtils.getLastThreeMonthDays(LocalDate.now());
        } else {
            List<LocalDate> recent12Months = TimesUtils.getRecent12Months(LocalDate.now());
            lastMonthStartTime = recent12Months.get(0).toString();
            lastMonthDays = TimesUtils.getRecent12Months(LocalDate.now());
            b = false;
        }
        List<LastMonthSalesVolumeDTO> cqwlChannelTrainList = adsCqwlChannelMapper.getLastMonthSalesVolume(lastMonthStartTime, b, dto.getDirection());
        //创建返回集合
        return getBoxVolume(lastMonthDays, cqwlChannelTrainList, b);
    }

    /**
     * @param startYear      今年上个月开始时间
     * @param endYear        今年结束时间
     * @param startLastYear  去年开始时间
     * @param endLastYear    去年结束时间
     * @param startMonth     这个月开始时间
     * @param endMonth       这个月结束时间
     * @param startLastMonth 上个月开始时间
     * @param endLastMonth   上个月结束时间
     * @return List<BoxTrendVO>
     */
    @Override
    public List<BoxTrendVO> getBoxTrend(LocalDate startYear, LocalDate endYear, LocalDate startLastYear, LocalDate endLastYear, LocalDate startMonth, LocalDate endMonth, LocalDate startLastMonth, LocalDate endLastMonth) {
        //查询今年走向数据
        List<BoxTrendDto> thisYearList = adsCqwlChannelMapper.getBoxTrend(startYear, endYear);
        //查询去年走向数据
        List<BoxTrendDto> lastYearList = adsCqwlChannelMapper.getBoxTrend(startLastYear, endLastYear);
        //查询这个月走向数据
        List<BoxTrendDto> thisMonthList = adsCqwlChannelMapper.getBoxTrend(startMonth, endMonth);
        //查询上个月走向数据
        List<BoxTrendDto> lastMonthList = adsCqwlChannelMapper.getBoxTrend(startLastMonth, endLastMonth);
        //拼接返回集计算同比
        List<BoxTrendVO> boxTrendTongBiList = new ArrayList<>();
        if (!thisYearList.isEmpty() && !lastYearList.isEmpty()) {
            lastYearList.forEach(lastYear -> {
                thisYearList.forEach(thisYear -> {
                    if (lastYear.getDirection().equals(thisYear.getDirection())) {
                        BoxTrendVO boxTrendVO = new BoxTrendVO();
                        boxTrendVO.setName(thisYear.getDirection());
                        boxTrendVO.setValue(thisYear.getTotal());
                        //计算同比率
                        boxTrendVO.setRate1(calculateTongBiRate(Double.parseDouble(lastYear.getTotal()), Double.parseDouble(thisYear.getTotal())));
                        boxTrendTongBiList.add(boxTrendVO);
                    }
                });
            });
        }
        List<BoxTrendVO> boxTrendHuBiList = new ArrayList<>();
        //计算环比率
        if (!thisMonthList.isEmpty() && !lastMonthList.isEmpty()) {
            lastMonthList.forEach(lastMonth -> {
                thisMonthList.forEach(thisMonth -> {
                    if (lastMonth.getDirection().equals(thisMonth.getDirection())) {
                        BoxTrendVO boxTrendVO = new BoxTrendVO();
                        boxTrendVO.setName(thisMonth.getDirection());
                        //计算环比率
                        boxTrendVO.setRate2(calculateTongBiRate(Double.parseDouble(lastMonth.getTotal()), Double.parseDouble(thisMonth.getTotal())));
                        boxTrendHuBiList.add(boxTrendVO);
                    }
                });
            });

        }
        //合并两个集合拼接返回集(暂时先把有的弄出来,后面再来改bug)
        boxTrendTongBiList.forEach(boxTrendHuBi -> {
            boxTrendHuBiList.forEach(boxTrendTongBi -> {
                if (boxTrendHuBi.getName().equals(boxTrendTongBi.getName())) {
                    boxTrendHuBi.setRate2(boxTrendTongBi.getRate2());
                }
            });
        });
        //处理数据,要求大屏统计数据次接口的返回数据一致,之前不一致是因为时间维度不同
       List<LastMonthSalesVolumeDTO> thisYearTotal = adsCqwlChannelMapper.getThisYearTotal();
        boxTrendTongBiList.forEach(boxTrendTongBi -> {
            thisYearTotal.forEach(thisYear -> {
                if (boxTrendTongBi.getName().equals(thisYear.getDirection())) {
                    boxTrendTongBi.setValue(thisYear.getTotal());
                }
            });
        });
        return boxTrendTongBiList;
    }

    /**
     * 精品路线列表
     *
     * @param dto 方位包装
     * @return List<BoxVolumeVO>
     */
    @Override
    public List<BoxVolumeVO> premiumRouteList(BoxTrendDto dto) {
        return adsCqwlChannelMapper.getPremiumRouteList(dto);

    }

    /**
     * 大屏1右3 运输方式
     *
     * @return List<BoxVolumeVO>
     */
    @Override
    public List<BoxVolumeVO> getTransportationMode() {

        return adsCqwlChannelMapper.getTransportationMode();
    }

    /**
     * 大屏1中间年度统计
     *
     * @return List<YearStatisticsVO>
     */
    @Override
    public List<YearStatisticsVO> getYearStatistics(BoxTrendDto dto) {
        // 创建返回集合
        List<YearStatisticsVO> returnList = new ArrayList<>();

        // 获取本年货运量
        StatisticsDto statistics = adsCqwlChannelMapper.getYearStatistics(dto);
        //获取今日货运箱量
        String todayStatistics = adsCqwlChannelMapper.getTodayStatistics(dto);
        //获取今年班列数和各个渠道的班列量
        StatisticsDto trainNum = adsCqwlChannelMapper.getTrainNum(dto);

        // 提供默认值
        StatisticsDto defaultStatistics = Optional.ofNullable(statistics).orElse(new StatisticsDto());
        StatisticsDto defaultTrainNum = Optional.ofNullable(trainNum).orElse(new StatisticsDto());

        // 使用默认值避免空指针
        statistics = defaultStatistics;
        trainNum = defaultTrainNum;


        //今日箱量(无下拉)
        YearStatisticsVO todayStatisticsVO = new YearStatisticsVO();
        todayStatisticsVO.setName("今日箱量");
        todayStatisticsVO.setValue(getOrDefault(todayStatistics));
        //年度货值总量(无下拉)
        YearStatisticsVO yearStatistics = new YearStatisticsVO();
        yearStatistics.setName("本年货值总量");
        yearStatistics.setValue(TimesUtils.removeTrailingZeros(statistics.getGoodsValue()));
        //数据有问题先处理下
        fixParm(trainNum);
        // 填充前端要求的返回格式
        List<DataGroupDTO> dataGroupList2 = createDataGroups2(statistics);

        YearStatisticsVO trainNumStatistics = new YearStatisticsVO();
        trainNumStatistics.setName("本年班列数");
        trainNumStatistics.setValue(TimesUtils.removeTrailingZeros(trainNum.getTotal()));
        trainNumStatistics.setDataItems(dataGroupList2);
        // 先拼接最里面的集合详情
        List<DataGroupDTO> dataGroupList1 = createDataGroups1(statistics);

        // 创建并填充 YearStatisticsVO 对象
        YearStatisticsVO total = new YearStatisticsVO();
        total.setName("本年货运总量");
        total.setValue(statistics.getTotal());
        total.setDataItems(dataGroupList1);


        // 添加到返回列表
        returnList.add(total);
        returnList.add(todayStatisticsVO);
        returnList.add(yearStatistics);
        returnList.add(trainNumStatistics);
        // 返回最终的统计数据列表
        return returnList;
    }

    /**
     * 大屏1右2精品路线详情
     * 目前按照传入终点,查询终点站是传入值的所有路线信息
     *
     * @param dto 获取里面的终点站destinationStation
     * @return List<DataGroupDTO>
     */
    @Override
    public List<BoxVolumeVO> premiumRouteDetails(RouteDTO dto) {
        //获取终点站为传入值的所有路线信息
        List<BoxVolumeVO> boxVolumeVOList = adsCqwlChannelMapper.premiumRouteDetails(dto.getDestinationStation());
        //获取去年的开始时间
        LocalDate startYear = LocalDate.of(LocalDate.now().getYear() - 1, 1, 1);
        //获取去年的今天的结束时间
        LocalDate endTime = LocalDate.now().minus(1, ChronoUnit.YEARS);
        List<BoxVolumeVO> boxVolumeVOList1=  adsCqwlChannelMapper.premiumRouteDetailsLast(dto.getDestinationStation(),startYear,endTime);
        return   calculateGrowthRate(boxVolumeVOList, boxVolumeVOList1);

    }

    private List<BoxVolumeVO> calculateGrowthRate(List<BoxVolumeVO> boxVolumeVOList, List<BoxVolumeVO> boxVolumeVOList1) {
        Map<String, BoxVolumeVO> mapA = new HashMap<>();
        for (BoxVolumeVO item : boxVolumeVOList) {
            mapA.put(item.getName(), item);
        }

        List<BoxVolumeVO> resultList = new ArrayList<>();
        for (BoxVolumeVO itemB : boxVolumeVOList1) {
            BoxVolumeVO itemA = mapA.get(itemB.getName());
            if (itemA != null) {
                BoxVolumeVO newItem = new BoxVolumeVO();
                newItem.setId(itemA.getId());
                newItem.setName(itemA.getName());
                newItem.setValue(itemA.getValue());
                newItem.setDate(itemA.getDate());
                newItem.setTripBack(itemA.getTripBack());
                newItem.setTransportationMode(itemA.getTransportationMode());
                newItem.setDistance(itemA.getDistance());
                newItem.setEfficiency(itemA.getEfficiency());

                double valueA = Double.parseDouble(itemA.getValue());
                double valueB = Double.parseDouble(itemB.getValue());
                newItem.setGrowthRate(calculateTongBiRate(valueB, valueA));

                resultList.add(newItem);
            } else {
                BoxVolumeVO newItem = new BoxVolumeVO();
                newItem.setId(itemB.getId());
                newItem.setName(itemB.getName());
                newItem.setValue(itemB.getValue());
                newItem.setDate(itemB.getDate());
                newItem.setTripBack(itemB.getTripBack());
                newItem.setTransportationMode(itemB.getTransportationMode());
                newItem.setDistance(itemB.getDistance());
                newItem.setEfficiency(itemB.getEfficiency());
                newItem.setGrowthRate("0");

                resultList.add(newItem);
            }
        }

        return resultList;
    }

    /**
     * 物流大屏2左1箱量走势
     *
     * @param dto type:1:近30天 2:最近3个月 3:最近1年  destinationStation:目的地
     * @return List<DataGroupDTO> 按照前端给定格式返回
     */
    @Override
    public List<DataGroupDTO> boxPlotDataWithRoute(BoxVolumeDTO dto) {
        String lastMonthStartTime;
        List<LocalDate> lastMonthDays;
        //标记区分sql查询按照天还是月
        boolean b = true;
        int type = Optional.ofNullable(dto.getType()).orElse(3);
        if (type == 1) {
            lastMonthStartTime = TimesUtils.getLastMonthStartTime(LocalDate.now());
            //获取最近一个月每一天的Date类型的日期
            lastMonthDays = TimesUtils.getLastMonthDays(LocalDate.now());
        } else if (type == 2) {
            //90天数据
            lastMonthStartTime = TimesUtils.getLastThreeMonthStartTime(LocalDate.now());
            lastMonthDays = TimesUtils.getLastThreeMonthDays(LocalDate.now());
        } else {
            List<LocalDate> recent12Months = TimesUtils.getRecent12Months(LocalDate.now());
            lastMonthStartTime = recent12Months.get(0).toString();
            lastMonthDays = TimesUtils.getRecent12Months(LocalDate.now());
            b = false;
        }
        List<BoxVolumeVO> dataWithRouteDTOList = adsCqwlChannelMapper.boxPlotDataWithRoute(lastMonthStartTime, b, dto.getDestinationStation());
        if (CollectionUtils.isEmpty(dataWithRouteDTOList)) {
            return null;
        }
        return getBoxVolume2(lastMonthDays, dataWithRouteDTOList, b);
    }

    /**
     * 物流大屏2左2 近半年货运量同比环比--按照6个月来计算就需要把日期往前提一个月
     *
     * @return List<Map < String, Object>>
     */
    @Override
    public List<Map<String, Object>> getBoxTrendWithRoute(RouteDTO dto) {
        List<Map<String, Object>> result = new ArrayList<>();
        // 近半年数据,这里多返回一个月数据是前端要求返回他好做环比
        String lastHalfYearStartTime = TimesUtils.getLastHalfYearStartTime(LocalDate.now(), 6L);
        List<BoxVolumeVO> dataWithRouteDTOList = adsCqwlChannelMapper.getBoxTrendWithRouteLastHalfYear(dto, lastHalfYearStartTime);
        addData(result, "近半年数据", LocalDate.now().minusMonths(6), dataWithRouteDTOList);


        List<LocalDate> localDates = TimesUtils.calculatePeriodDates(LocalDate.now());


        // 同比数据(去年开始时间和结束时间)
        List<BoxVolumeVO> dataWithRouteDTOList1 = adsCqwlChannelMapper.getBoxTrendWithRouteLastHalfYearTongbi(dto, localDates.get(0), localDates.get(1));
        addData(result, "同比数据", localDates.get(0), dataWithRouteDTOList1);
        return result;
    }

    /**
     * 大屏2中间获取线路
     *
     * @param dto destinationStation 借用表示路过站点-对应DB的port
     */
    @Override
    public LineNameSumMarVO getMapList(PortStationDTO dto) {
        List<BoxVolumeVO> dataWithRoute = adsCqwlChannelMapper.getMapList(dto.getPortStation());
        //组装下数据
        LineNameSumMarVO lineNameSumMarVO = new LineNameSumMarVO();
        lineNameSumMarVO.setLineNameList(dataWithRoute);
        // 使用Stream API对集合进行处理
        Map<String, Integer> tripBackSumMap = dataWithRoute.stream()
                //数据查询出来有小数点,所以先转double再转int
                .collect(Collectors.groupingBy(BoxVolumeVO::getTripBack, Collectors.summingInt(vo -> (int) Double.parseDouble(vo.getValue()))));
        for (Map.Entry<String, Integer> entry : tripBackSumMap.entrySet()) {
            if ("回程".equals(entry.getKey())) {
                lineNameSumMarVO.setBackTeu(String.valueOf(entry.getValue()));
            } else {
                lineNameSumMarVO.setForwardTeu(String.valueOf(entry.getValue()));
            }
        }
        return lineNameSumMarVO;
    }

    /**
     * 获取货物排行榜
     *
     * @return List<BoxVolumeVO>
     */
    @Override
    public List<BoxVolumeVO> getGoodsRanking(RouteDTO dto) {
        return adsCqwlChannelMapper.getGoodsRanking(dto.getDestinationStation());
    }


    private static void addData(List<Map<String, Object>> result, String name, LocalDate startDate, List<BoxVolumeVO> dataWithRouteDTOList) {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("name", name);
        dataMap.put("data", generateData(startDate, dataWithRouteDTOList));
        result.add(dataMap);
    }

    private static List<Map<String, String>> generateData(LocalDate startDate, List<BoxVolumeVO> dataWithRouteDTOList) {
        return IntStream.range(0, dataWithRouteDTOList.size())
                .mapToObj(i -> {
                    LocalDate date = startDate.plusMonths(i);
                    return createData(date, dataWithRouteDTOList);
                })
                .collect(Collectors.toList());
    }

    /**
     * 组装数据并返回
     */
    private static Map<String, String> createData(LocalDate name, List<BoxVolumeVO> dataWithRouteDTOList) {
        Map<String, String> data = new HashMap<>();
        data.put("name", String.format("%d年%d月", name.getYear(), name.getMonthValue()));
        data.put("value", "0");
        dataWithRouteDTOList.forEach(boxVolumeVO -> {
            if (Integer.parseInt(boxVolumeVO.getName().split("-")[0]) == name.getYear() && Integer.parseInt(boxVolumeVO.getName().split("-")[1]) == name.getMonthValue()) {
                data.put("value", boxVolumeVO.getValue());
            }
        });
        return data;
    }

    /**
     * 处理数据
     */
    private static void fixParm(StatisticsDto trainNum) {
        String realImportTeu = TimesUtils.removeTrailingZeros(trainNum.getImportTeu());
        trainNum.setImportTeu(realImportTeu);
        String realExportTeu = TimesUtils.removeTrailingZeros(trainNum.getExportTeu());
        trainNum.setExportTeu(realExportTeu);
        String realHeavyContainers = TimesUtils.removeTrailingZeros(trainNum.getHeavyContainers());
        trainNum.setHeavyContainers(realHeavyContainers);
        String realEmptyContainers = TimesUtils.removeTrailingZeros(trainNum.getEmptyContainers());
        trainNum.setEmptyContainers(realEmptyContainers);
    }

    private List<DataGroupDTO> createDataGroups1(StatisticsDto statistics) {
        List<DataGroupDTO> dataGroupList = new ArrayList<>();

        // 创建并添加 "进/出口" 数据组
        dataGroupList.add(createDataGroup("进/出口",
                createBoxVolumeVO("进口", statistics.getImportTeu()),
                createBoxVolumeVO("出口", statistics.getExportTeu())));

        // 创建并添加 "重/空箱" 数据组
        dataGroupList.add(createDataGroup("重/空箱",
                createBoxVolumeVO("重箱", statistics.getHeavyContainers()),
                createBoxVolumeVO("空箱", statistics.getEmptyContainers())));

        return dataGroupList;
    }

    private List<DataGroupDTO> createDataGroups2(StatisticsDto statistics) {
        List<DataGroupDTO> dataGroupList = new ArrayList<>();

        if (statistics != null) {
            // 创建并添加 "进/出口" 数据组
            dataGroupList.add(createDataGroup("本年班列",
                    createBoxVolumeVO("国际铁路", getOrDefault(statistics.getExportTeu())),
                    createBoxVolumeVO("跨境公路", getOrDefault(statistics.getHeavyContainers())),
                    createBoxVolumeVO("长江航运", getOrDefault(statistics.getEmptyContainers()))
            ));
        }

        return dataGroupList;
    }

    private String getOrDefault(String value) {
        return Optional.ofNullable(value).orElse("0");
    }

    private DataGroupDTO createDataGroup(String name, BoxVolumeVO... boxVolumes) {
        DataGroupDTO dataGroup = new DataGroupDTO();
        dataGroup.setName(name);
        dataGroup.setData(Arrays.asList(boxVolumes));
        return dataGroup;
    }

    private BoxVolumeVO createBoxVolumeVO(String name, String value) {
        BoxVolumeVO boxVolumeVO = new BoxVolumeVO();
        boxVolumeVO.setName(name);
        boxVolumeVO.setValue(value);
        return boxVolumeVO;
    }


    /**
     * 计算同比率,环比率
     */
    public String calculateTongBiRate(double lastYearValue, double thisYearValue) {
        if (lastYearValue == 0) {
           return "0";
        }
        double rate = (thisYearValue - lastYearValue) / lastYearValue * 100;
        // 保留两位小数
        return Math.round(rate * 100.0) / 100.0 + "%";
    }

    /**
     * 转换数据
     *
     * @param lastMonthDays        开始时间
     * @param cqwlChannelTrainList db查询出来的数据
     * @return List<BoxVolumeVO>
     */
    public List<BoxVolumeVO> getBoxVolume(List<LocalDate> lastMonthDays, List<LastMonthSalesVolumeDTO> cqwlChannelTrainList, Boolean b) {
        List<BoxVolumeVO> boxVolumeList = new ArrayList<>();
        lastMonthDays.forEach(date -> {
            BoxVolumeVO boxVolumeVO = new BoxVolumeVO();
            boxVolumeVO.setName(TimesUtils.getDateString(date, b));
            boxVolumeVO.setValue("0");
            cqwlChannelTrainList.forEach(cqwlChannelTrain -> {
                if (date.equals(cqwlChannelTrain.getDate())) {
                    boxVolumeVO.setValue(cqwlChannelTrain.getTotal());
                }
            });
            boxVolumeList.add(boxVolumeVO);
        });
        return boxVolumeList;
    }

    public List<DataGroupDTO> getBoxVolume2(List<LocalDate> lastMonthDays, List<BoxVolumeVO> dataWithRouteDTOList, Boolean b) {
        //按照航线分组并转换成对象
        Map<String, List<BoxVolumeVO>> groupedItems = dataWithRouteDTOList.stream()
                .collect(Collectors.groupingBy(BoxVolumeVO::getName));
        List<DataGroupDTO> result = new ArrayList<>();

        for (Map.Entry<String, List<BoxVolumeVO>> entry : groupedItems.entrySet()) {
            DataGroupDTO dataGroupDTO = new DataGroupDTO();
            dataGroupDTO.setName(entry.getKey());
            List<BoxVolumeVO> boxVolumeList = new ArrayList<>();

            for (LocalDate date : lastMonthDays) {
                BoxVolumeVO boxVolumeVO = new BoxVolumeVO();
                boxVolumeVO.setName(TimesUtils.getDateString(date, b));
                boxVolumeVO.setValue("0");

                for (BoxVolumeVO cqwlChannelTrain : entry.getValue()) {
                    if (date.equals(cqwlChannelTrain.getDate())) {
                        boxVolumeVO.setValue(cqwlChannelTrain.getValue());
                    }
                }
                boxVolumeList.add(boxVolumeVO);
            }
            dataGroupDTO.setData(boxVolumeList);
            result.add(dataGroupDTO);
        }
        return result;
    }


}
